﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using KPIS.GERP.Models;
using KPIS.GERP.Models.Class;
using KPIS.GERP.Models.HRM;
using KPIS.GERP.Models.SYS;
using KPIS.GERP.Models.SYS.ViewModel;
using System.Data.Entity;

namespace KPIS.GERP.WCF.SYS
{
    public partial class SysApprovalService : ISysApprovalService
    {
        public CheckAbsenceRuleResultVM CheckAbsenceRule(int empId, int? absenceId, int absenceTypeId,
                                                         DateTime startDate, DateTime endDate, string contactAddress, string description,
                                                         int createdBy, string startTime, string endTime, string requestTitle)
        {
            var u = new AbsenceUtility();
            var db = new GERPContext(true);
            var dbCloseProxy = new GERPContext(false);
            CheckAbsenceRuleResultVM model = new CheckAbsenceRuleResultVM();
            model.AbsenceId = absenceId;
            model.AbsenceTypeId = absenceTypeId;
            model.BgYear = startDate.BuddhistBgYear();
            var currentAbsence = absenceId.HasValue && absenceId != 0 ? db.PsAbsences.FirstOrDefault(o => o.AbsenceId == absenceId && o.RecordStatus != "D") : null;
            model.CreateDate = currentAbsence != null && currentAbsence.CreatedWhen.HasValue ? currentAbsence.CreatedWhen.Value : DateTime.Now;
            model.EmpId = empId;
            model.StartDate = startDate;
            model.EndDate = endDate;
            model.StartTime = startTime;
            model.EndTime = endTime;
            model.CreateBy = createdBy;

            #region Find Error Message/Warning Message

            var list_message_warning = db.MessageWarnings.ToList();

            // Load message warning
            string กำลังเตรียมการ = list_message_warning.First(r => r.MessageId == 1).MessageTh;
            string ค้นหาข้อมูลพนักงาน = list_message_warning.First(r => r.MessageId == 2).MessageTh;
            string ไม่พบข้อมูลพนักงาน = list_message_warning.First(r => r.MessageId == 3).MessageTh;
            string ค้นหาเงื่อนไขการลา = list_message_warning.First(r => r.MessageId == 4).MessageTh;
            string ไม่พบเงื่อนไขการลา = list_message_warning.First(r => r.MessageId == 5).MessageTh;

            string ค้นหาประวัติการลา = list_message_warning.First(r => r.MessageId == 6).MessageTh;
            string เริ่มตรวจสอบเงื่อนไขการลา = list_message_warning.First(r => r.MessageId == 7).MessageTh;
            string ตรวจสอบจำนวนครั้งในการลา = list_message_warning.First(r => r.MessageId == 8).MessageTh;
            string ลาเกินจำนวนครั้งที่กำหนด = list_message_warning.First(r => r.MessageId == 9).MessageTh;
            string ตรวจสอบวันยื่นใบลา = list_message_warning.First(r => r.MessageId == 10).MessageTh;

            string วันที่ยื่นใบลาไม่ถูกต้อง = list_message_warning.First(r => r.MessageId == 11).MessageTh;
            string ตรวจสอบจำนวนวันลาต่อครั้ง = list_message_warning.First(r => r.MessageId == 12).MessageTh;
            string ลาเกินจำนวนวันลาต่อครั้ง = list_message_warning.First(r => r.MessageId == 13).MessageTh;
            string ตรวจสอบจำนวนวันลา = list_message_warning.First(r => r.MessageId == 14).MessageTh;
            string ลาเกินจำนวนที่กำหนด = list_message_warning.First(r => r.MessageId == 15).MessageTh;

            string ตรวจสอบเงื่อนไขก่อนยื่นอนุมัติ = list_message_warning.First(r => r.MessageId == 16).MessageTh;
            string รอการอนุมัติ = list_message_warning.First(r => r.MessageId == 17).MessageTh;
            string เงื่อนไขไม่ถูกต้อง = list_message_warning.First(r => r.MessageId == 18).MessageTh;
            string ส่งต่อเพื่อรออนุมัติ = list_message_warning.First(r => r.MessageId == 19).MessageTh;
            string ส่งกลับเพื่อแก้ไข = list_message_warning.First(r => r.MessageId == 20).MessageTh;

            string ผ่านการอนุมัติ = list_message_warning.First(r => r.MessageId == 21).MessageTh;
            string ไม่ผ่านการอนุมัติ = list_message_warning.First(r => r.MessageId == 22).MessageTh;
            string เงื่อนไขถูกต้อง = list_message_warning.First(r => r.MessageId == 23).MessageTh;
            string ยกเลิกคำร้อง = list_message_warning.First(r => r.MessageId == 24).MessageTh;

            #endregion


            //#1
            var employee = db.Employees.Include(o=>o.MasNamePrefix.MasGender).FirstOrDefault(o => o.RecordStatus != "D" && o.EmpId == empId);
            
            if(employee == null)
            {
                return model.Error("ตรวจสอบข้อมูลพนักงาน", ไม่พบข้อมูลพนักงาน);
            } else
            {
                // this is regular check, should rarely found error, hide message
                // model.Ok("ตรวจสอบข้อมูลพนักงาน", string.Format("พบข้อมูลพนักงาน :{0}", employee.FullName));
            }

            //#2
            if(employee.MasEmployeeType == null)
            {
                return model.Error("ตรวจสอบประเภทบุคคลากร", "ไม่พบประเภทบุคคลากร");
            } else
            {
                // this is regular check, should rarely found error, hide message
                // model.Ok("ตรวจสอบประเภทบุคคลากร", string.Format("พบประเภทบุคคลากร :{0}", employee.MasEmployeeType.Name));
            }

            //#3
            var absenceType = db.PsAbsenceTypes.FirstOrDefault(o => o.AbsenceTypeId == absenceTypeId && o.RecordStatus != "D");
            if(absenceType == null)
            {
                return model.Error("ตรวจสอบประเภทคำขอ", "ไม่พบประเภทคำขอ");
            } else
            {
                // this is regular check, should rarely found error, hide message
                // model.Ok("ตรวจสอบประเภทคำขอ", string.Format("พบประเภทคำขอ :{0}", absenceType.AbsenceTypeName));
            }
            model.Msg("ผลการตรวจสอบการ" + absenceType.AbsenceTypeName + " ของ", "" + employee.FullName + " (" + employee.MasEmployeeType.Name + ")");
            
            
            //#4
            if(employee.GenderId != null && employee.GenderId == 2 && absenceTypeId == 6) // ทหาร
            {
                return model.Error("ตรวจสอบความถูกต้องของประเภทคำขอกับผู้ขอ", string.Format("{0}คำขอลาเข้ารับราชการทหารเป็นคำขอสำหรับผู้ชายเท่านั้น ผู้หญิงไม่สามารถทำคำขอนี้ได้", เงื่อนไขไม่ถูกต้อง));
            } else if(employee.MasNamePrefix != null && employee.GenderId == 1 && absenceTypeId == 2) // ลาคลอดบุตร
            {
                return model.Error("ตรวจสอบความถูกต้องของประเภทคำขอกับผู้ขอ", string.Format("{0}คำขอลาคลอดบุตรเป็นคำขอสำหรับผู้หญิงเท่านั้น ผู้ชายไม่สามารถทำคำขอนี้ได้", เงื่อนไขไม่ถูกต้อง));
            } else
            {
                // this is regular check, should rarely found error, hide message
                // model.Ok("ตรวจสอบความถูกต้องของประเภทคำขอกับผู้ขอ", "ผ่าน");
            }

            //#5
            model.RuleAbsence = dbCloseProxy.RuleAbsences.FirstOrDefault(o => o.AbsenceTypeId == absenceTypeId && o.EmpTypeId == employee.EmpTypeId && o.RecordStatus != "D"); 
            if(model.RuleAbsence == null)
            {
                string additionalStr = " (สำหรับประเภทบุคคลากร [" + employee.MasEmployeeType.Name + "] และ ประเภทคำขอลา ["  + absenceType.AbsenceTypeName + "], กรุณาติดต่อฝ่ายบุคคลากรให้เพิ่มเงื่อนไขการลานี้)";
                return model.Error("ตรวจสอบเงื่อนไขการลาภายใต้ประเภทบุคคลากร", ไม่พบเงื่อนไขการลา + additionalStr);
            } else
            {
                // this is regular check, should rarely found error, hide message
                // model.Ok("ตรวจสอบเงื่อนไขการลาภายใต้ประเภทบุคคลากร", "พบเงื่อนไขการลา");
            }
            model.DayLimit = model.RuleAbsence.DayLimit ?? 0;

            var otherAbsenceOfThisEmp = db.PsAbsences
                .Where(o => o.EmpId == empId &&  o.AbsenceId != absenceId 
                    && (o.RecordStatus == "A" || o.RecordStatus == "P") 
                    && o.AbsenceTypeId == absenceTypeId 
                    && o.BgYear == model.BgYear);
            foreach (var absence in otherAbsenceOfThisEmp)
            {
                model.MyAllTimeCount += absence.TimeCount ?? 0;
                model.MyAllDayCount += absence.DayCount ?? 0;
            }
            model.QuotaLeaveCountDaysBefore = (model.RuleAbsence.DayLimit??0) - model.MyAllDayCount;
            
            //#6 Time count
            model.RequestTimeCount = 1;
            model.MyAllAndRequestTimeCount = model.MyAllTimeCount + model.RequestTimeCount;
            if (model.RuleAbsence.TimeLimit.HasValue && model.RuleAbsence.TimeLimit != 0 && 
                model.MyAllAndRequestTimeCount > model.RuleAbsence.TimeLimit)
            {
                // ลาเกินจำนวนครั้งที่กำหนด
                var msg = string.Format("{0} (จำนวนครั้งที่กำหนดสำหรับการลาประเภทนี้คือ {1}, จำนวนครั้งที่ลาในคำขอนี้คือ {2}, รวมกับคำขออื่นๆ ของคุณคือ {3})", 
                    ลาเกินจำนวนครั้งที่กำหนด, 
                    model.RuleAbsence.TimeLimit, 
                    1,
                    model.MyAllAndRequestTimeCount); 
                return model.Error("ตรวจสอบจำนวนครั้งการลา", msg);
            }
            else
            {
                string titleMsg = "";
                if(model.RuleAbsence.TimeLimit.HasValue && model.RuleAbsence.TimeLimit != 0)
                {
                    titleMsg += string.Format("ไม่ให้เกินกว่า {0} ครั้งต่อปี", model.RuleAbsence.TimeLimit.Value.ToString("#,###"));
                } else
                {
                    titleMsg += string.Format("ไม่จำกัดจำนวนครั้งการลาต่อปี");
                }
                model.Ok(titleMsg, string.Format("จำนวนที่ลาแล้วทั้งปี รวมครั้งนี้ {0} ครั้ง (นับเฉพาะการลาประเภทเดียวกัน)", model.MyAllAndRequestTimeCount));
            }
            
            //#7 
            int submitBeforehandDay;
            int workingDay = u.GetRegularWorkingDays(model.CreateDate.Date, model.StartDate.Date);
            submitBeforehandDay = (workingDay - 1) * (model.CreateDate.Date > model.StartDate.Date ? -1 : 1 );
            string wordingSubmitBeforehandDay = "", wordingSendBefore = "",wordingDay = "ยื่น" + (absenceId.HasValue ? "(ครั้งแรก)":"") + " " + model.CreateDate.ToShortDateStringBuddhist() + " เริ่มลา " + model.StartDate.ToShortDateStringBuddhist();
            if(submitBeforehandDay > 0)
            {
                wordingSubmitBeforehandDay = "ยื่นล่วงหน้า " + submitBeforehandDay + " วัน";
            } else if(submitBeforehandDay == 0)
            {
                wordingSubmitBeforehandDay = "ยื่นวันเดียวกับวันเริ่มลา";
            } else
            {
                wordingSubmitBeforehandDay = "ยื่นย้อนหลัง " + (submitBeforehandDay*-1) + " วัน";
            }

            if(model.RuleAbsence.SendBefore > 0)
            {
                wordingSendBefore = "ท่านต้องยื่นล่วงหน้าอย่างน้อย " + model.RuleAbsence.SendBefore + " วัน";
            } else if(model.RuleAbsence.SendBefore == 0 || model.RuleAbsence.SendBefore == null)
            {
                wordingSendBefore = "ท่านไม่ต้องยื่นล่วงหน้า";
            } else
            {
                wordingSendBefore = "ท่านสามารถยื่นย้อนหลังได้ไม่เกิน " + (model.RuleAbsence.SendBefore*-1) + " วัน";
            }                
                
            string reasons = string.Format("เพราะท่าน{0} ท่าน{1}(คำนวนเฉพาะวันทำงาน)", wordingDay, wordingSubmitBeforehandDay);
            if (!model.RuleAbsence.SendBefore.HasValue ||
                submitBeforehandDay >= model.RuleAbsence.SendBefore)
            {
                // OK
                model.Ok(wordingSendBefore, "ท่านสามารถยื่นได้ " + reasons);
            } else {
                // Not Ok
                model.Error(wordingSendBefore, "ท่านไม่สามารถยื่นได้ " + reasons);
            }

            bool เริ่มเช้า = model.StartTime.Equals("M");
            bool ถึงบ่าย = model.EndTime.Equals("A");
            Decimal n = 0;
            if (model.StartDate.Date.Equals(model.EndDate.Date))
            {
                n = u.GetRegularWorkingDays(model.StartDate.Date, model.StartDate.Date);
                if (n >= 1)
                {
                    if (เริ่มเช้า && ถึงบ่าย) n = 1;
                    else if (!เริ่มเช้า && ถึงบ่าย) n = (Decimal) 0.5;
                    else if (เริ่มเช้า && !ถึงบ่าย) n = (Decimal) 0.5;
                    else n = 0;
                }
            }
            else if (model.StartDate.Date < model.EndDate.Date)
            {
                n = u.GetRegularWorkingDays(model.StartDate.Date, model.EndDate.Date);
                if (n >= 1)
                {
                    if (เริ่มเช้า && ถึงบ่าย) n -= 0;
                    else if (!เริ่มเช้า && ถึงบ่าย) n -= (Decimal) 0.5;
                    else if (เริ่มเช้า && !ถึงบ่าย) n -= (Decimal) 0.5;
                    else if (!เริ่มเช้า && !ถึงบ่าย) n -= 1;
                    else n = 0;
                }
            }
            else
            {
                n = 0;
            }

            model.RequestDayCount = n;
            // #8 จำนวนวันลาต้องมากกว่า 0
            if (model.RequestDayCount == 0)
            {
                string msg = string.Format("{0} (จำนวนวันลาที่ยื่นขอนับเฉพาะวันทำงาน 0 วัน ต้องมีวันลาอย่างน้อยครึ่งวันขึ้นไป)", วันที่ยื่นใบลาไม่ถูกต้อง);
                return model.Error("ตรวจสอบความถูกต้องจำนวนวันลา", msg); 
            }else
            {
                // this is regular check
                model.Ok("ความถูกต้องจำนวนวันลา", "นับวันลาได้ " + model.RequestDayCount + " วัน (มีวันลาตั้งแต่ครึ่งวันขึ้นไป)");
            }
                
            // #9 จำนวนวันลา ควรจะน้อยกว่าโคว์ต้าที่เหลือ
            string leftQuotaTitle = "โควต้าที่เหลือ " + model.QuotaLeaveCountDaysBefore.ToString("#,##0.#") + " วัน";
            if(model.RequestDayCount > model.QuotaLeaveCountDaysBefore)
            { 
                string msg = string.Format("{0} (จำนวนวันลาที่ขอคือ {1} วัน ควรน้อยกว่าโควต้าที่เหลือ)", วันที่ยื่นใบลาไม่ถูกต้อง, model.RequestDayCount, model.QuotaLeaveCountDaysBefore);
                model.Warning(leftQuotaTitle, msg); 
            } else
            {
                string msg = string.Format("จำนวนวันลาที่ขอคือ {0} วัน", model.RequestDayCount);
                model.Ok(leftQuotaTitle, msg);
            }
                
            // #10 จำนวนวันลาต่อครั้ง ควรน้ยอกว่าที่กำหนด
            decimal dayPerTimeLimit = model.RuleAbsence.DayPerTimeLimit ?? 0;
            string dayPerTimeLimitTitle = dayPerTimeLimit == 0 ? "ไม่จำกัดวันลาต่อครั้ง" : "วันลาต่อครั้งไม่ควรเกิน " + dayPerTimeLimit + " วัน";
            if(dayPerTimeLimit <= 0 || model.RequestDayCount <= dayPerTimeLimit)
            {
                string msg = string.Format("จำนวนวันลาที่ขอคือ {0} วัน", model.RequestDayCount);
                model.Ok(dayPerTimeLimitTitle, msg);
            } else
            {
                string msg = string.Format("จำนวนวันลาที่ขอคือ {0} วัน มากกว่าจำนวนวันลาต่อครั้งที่กำหนด", model.RequestDayCount);
                model.Warning(dayPerTimeLimitTitle, msg); 
            }
            
            if(string.IsNullOrWhiteSpace(model.Remarks) && (!model.IsWarning && !model.IsWarning))
            {
                model.Remarks = model.GetMessageErrorAndWarning();
            } 

            return model;
        }

        public CheckAbsenceRuleResultVM InsertAbsence(CheckAbsenceRuleResultVM resultCheckRule,
            string contactAddress,
            string description,
            string requestTitle,
            int createBy)
        {
            var db = new GERPContext();

            //Insert_HrmPsAbsence
            {
                PsAbsence absence = new PsAbsence();
                absence.AbsenceTypeId = resultCheckRule.AbsenceTypeId;
                absence.Code = CodeGenerate.GetNextCode(CodeGenerate.TransectionType.Absence);
                absence.BgYear = resultCheckRule.BgYear;
                absence.EmpId = resultCheckRule.EmpId;
                absence.StartDate = resultCheckRule.StartDate;
                absence.StartTime = resultCheckRule.StartTime;
                absence.EndDate = resultCheckRule.EndDate;
                absence.EndTime = resultCheckRule.EndTime;
                absence.DayCount = resultCheckRule.RequestDayCount;
                absence.ContactAddress = contactAddress;
                absence.Remarks = resultCheckRule.GetMessageErrorAndWarning();
                absence.RecordStatus = "W";
                absence.CreatedBy = resultCheckRule.CreateBy;
                absence.CreatedWhen = DateTime.Now;
                absence.Description = description;
                absence.RequestTitle = requestTitle;

                db.PsAbsences.Add(absence);
                db.SaveChanges();
                resultCheckRule.Absence = absence;
                resultCheckRule.AbsenceId = absence.AbsenceId;
            }

            return resultCheckRule;
        }

        public CheckAbsenceRuleResultVM UpdateAbsence(CheckAbsenceRuleResultVM resultCheckRule,
            string contactAddress,
            string description,
            string requestTitle,
            int updateBy)
        {
            //Update_HrmPsAbsence
            using (var db = new GERPContext(true))
            {
                PsAbsence absence = db.PsAbsences.First(o => o.AbsenceId == resultCheckRule.AbsenceId);
                absence.AbsenceTypeId = resultCheckRule.AbsenceTypeId;
                absence.BgYear = resultCheckRule.BgYear;
                absence.EmpId = resultCheckRule.EmpId;
                absence.StartDate = resultCheckRule.StartDate;
                absence.StartTime = resultCheckRule.StartTime;
                absence.EndDate = resultCheckRule.EndDate;
                absence.EndTime = resultCheckRule.EndTime;
                absence.DayCount = resultCheckRule.RequestDayCount;
                absence.ContactAddress = contactAddress;
                absence.Remarks = resultCheckRule.GetMessageErrorAndWarning();
                absence.UpdatedBy = updateBy;
                absence.UpdatedWhen = DateTime.Now;
                absence.Description = description;
                absence.RequestTitle = requestTitle;

                db.SaveChanges();
            }

            // Return
            using (var db = new GERPContext(false))
            {
                resultCheckRule.Absence = db.PsAbsences
                    .Include(o=>o.AbsenceType)
                    .First(o => o.AbsenceId == resultCheckRule.AbsenceId);
            }
            return resultCheckRule;
        }

    }
}